package k8s_agent

import (
	"context"

	devcontainer_dto "code.gitea.io/gitea/modules/devstar_devcontainer/k8s_agent/dto"
	"code.gitea.io/gitea/modules/setting"
	devcontainer_service_dto "code.gitea.io/gitea/services/devstar_devcontainer/dto"
	apimachinery_meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	devcontainer_k8s_agent_module "code.gitea.io/gitea/modules/devstar_devcontainer/k8s_agent"
)

// 补充笔记： modules/ 与 services/ 两个目录中的 k8s Agent 区别是什么？
//    - modules/ 与 k8s API Server 交互密切相关
//    - services/ 进行了封装，简化用户界面使用

// AssignDevcontainerCreation2K8sOperator 将 DevContainer 资源创建任务派遣至 k8s Operator，同时根据结果更新 NodePort
//
//	注意：本方法仍然在数据库事务中，因此不适合执行长时间操作，故需要后期异步判断 DevContainer 是否就绪
func AssignDevcontainerCreation2K8sOperator(ctx *context.Context, newDevContainer *devcontainer_service_dto.CreateDevcontainerDTO) error {

	// 1. 获取 Dynamic Client
	client, err := devcontainer_k8s_agent_module.GetKubernetesClient(ctx)
	if err != nil {
		// 层层返回错误，结束数据库事务
		return err
	}

	// 2. 调用 modules 层 k8s Agent，执行创建资源
	opts := &devcontainer_dto.CreateDevcontainerOptions{
		CreateOptions: apimachinery_meta_v1.CreateOptions{},
		Name:          newDevContainer.Name,
		Namespace:     setting.Devstar.Devcontainer.Namespace,
		Image:         newDevContainer.Image,
		/**
		 * 配置 Kubernetes 主容器启动命令注意事项：
		 *  1. 确保 Image 中已安装 OpenSSH Server
		 *  2. 容器启动后必须拉起 OpenSSH 后台服务
		 *  3. 请勿使用 sleep infinity 或者 tail -f /dev/null 等无限等待命令，
		 *     可以考虑无限循环 sleep 60s，能够防止 k8s 中容器先变成 Completed 然后变为 CrashLoopBackOff
		 *     也可以防止造成大量僵尸(<defunct>)进程：
		 *      $ ps aux | grep "<defunct>"                                                            # 列举僵尸进程
		 *        USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
		 *        pollina+  2336  0.0  0.0      0     0 ?        Z    17:22   0:00 [sshd] <defunct>
		 *        pollina+ 10986  0.0  0.0      0     0 ?        Z    16:12   0:00 [sshd] <defunct>
		 *        pollina+ 24722  0.0  0.0      0     0 ?        Z    18:36   0:00 [sshd] <defunct>
		 *        pollina+ 26773  0.0  0.0      0     0 ?        Z    18:37   0:00 [sshd] <defunct>
		 *      $ ubuntu@node2:~$ ps o ppid 2336 10986 24722 26773                                     # 查询僵尸进程父进程PID
		 *				 PPID
		 *				21826
		 *      $ ps aux | grep                                                                        # 列举僵尸进程父进程详情
		 *        USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
		 *        root     21826  0.0  0.0   2520   408 ?        Ss   18:36   0:00 sleep infinity
		 */
		CommandList: []string{
			"/bin/bash",
			"-c",
			"rm -f /etc/ssh/ssh_host_* && ssh-keygen -A && service ssh start && while true; do sleep 60; done",
		},
		ContainerPort:    22,
		ServicePort:      22,
		SSHPublicKeyList: newDevContainer.SSHPublicKeyList,
		GitRepositoryURL: newDevContainer.GitRepositoryURL,
	}

	// 2. 创建成功，取回集群中的 DevContainer
	devcontainerInCluster, err := devcontainer_k8s_agent_module.CreateDevcontainer(ctx, client, opts)
	if err != nil {
		return err
	}

	// 3. 将分配的 NodePort Service 写回 newDevcontainer，供写入数据库进行下一步操作
	newDevContainer.DevcontainerPort = devcontainerInCluster.Status.NodePortAssigned

	// 4. 层层返回 nil，自动提交数据库事务，完成 DevContainer 创建
	return nil
}
